﻿using System.Web.Mvc;
using SDF.Core;
using SDF.Core.Caching;
using SDF.Plugin.Misc.DynamicEntity.Models;
using SDF.Services.Configuration;
using SDF.Services.Localization;
using SDF.Services.Media;
using SDF.Services.Projects;
using SDF.Web.Framework.Controllers;
using SDF.Web.Framework.Kendoui;
using SDF.Services.Security;
using SDF.Plugin.Misc.DynamicEntity.Services;
using System.Linq;
using SDF.Plugin.Misc.DynamicEntity.Extensions;
using SDF.Services.Helpers;
using System;
using SDF.Plugin.Misc.DynamicEntity.Domain;
using System.Collections.Generic;
using SDF.Web.Framework;
using Newtonsoft.Json.Linq;
using SDF.Plugin.Misc.DynamicEntity.Common;

namespace SDF.Plugin.Misc.DynamicEntity.Controllers
{
    [AdminAuthorize]
    public class DynamicEntityController : DEControlBase
    {
        private readonly IWorkContext _workContext;
        private readonly IProjectContext _projectContext;
        private readonly IProjectService _projectService;
        private readonly IPictureService _pictureService;
        private readonly ISettingService _settingService;
        private readonly ICacheManager _cacheManager;
        private readonly ILocalizationService _localizationService;
        private readonly IPermissionService _permissionService;
        private readonly IDynamicEntityService _entityService;
        private readonly IDateTimeHelper _dateTimeHelper;

        public DynamicEntityController(IWorkContext workContext,
            IProjectContext projectContext,
            IProjectService projectService,
            IPictureService pictureService,
            ISettingService settingService,
            ICacheManager cacheManager,
            ILocalizationService localizationService,
            IPermissionService permissionService,
            IDynamicEntityService dynamicService,
            IDateTimeHelper dateTimeHelper)
        {
            this._workContext = workContext;
            this._projectContext = projectContext;
            this._projectService = projectService;
            this._pictureService = pictureService;
            this._settingService = settingService;
            this._cacheManager = cacheManager;
            this._localizationService = localizationService;
            this._permissionService = permissionService;
            this._entityService = dynamicService;
            this._dateTimeHelper = dateTimeHelper;
        }

        public ActionResult HeaderList()
        {
            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/HeaderList.cshtml");
        }

        public ActionResult Create()
        {
            var model = new DynamicEntityHeaderModel();

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/Create.cshtml", model);
        }

        [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
        public ActionResult Create(DynamicEntityHeaderModel model, bool continueEditing)
        {
            if (ModelState.IsValid)
            {
                var entity = new DynamicEntityHeader();
                entity = model.ToEntity(entity);

                _entityService.InsertEntity(entity);

                SuccessNotification(_localizationService.GetResource("Plugins.Misc.DynamicEntity.CreateSuccess"));

                if (continueEditing)
                {
                    return RedirectToAction("EditHeader", new { id = entity.Id });
                }
                return RedirectToAction("HeaderList");
            }

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/Create.cshtml", model);
        }

        [HttpPost]
        public ActionResult DeleteHeader(int id)
        {
            var header = _entityService.GetEntityById(id);
            if (header == null)
            {
                return RedirectToAction("HeaderList");
            }

            _entityService.DeleteEntities(new List<DynamicEntityHeader>() { header });

            SuccessNotification(_localizationService.GetResource("Plugins.Misc.DynamicEntity.DeleteSuccess"));

            return RedirectToAction("HeaderList");
        }

        [HttpPost]
        public ActionResult DeleteHeaders(int[] headerIds)
        {
            headerIds.NullCheck("headerIds");
            headerIds.Any().FalseThrow("headerIds");

            var headers = _entityService.GetEntitiesByIds(headerIds);
            if (headers == null || headers.Any() == false)
            {
                return new JsonResult()
                {
                    Data = _localizationService.GetResource("Plugins.Misc.DynamicEntity.Entity.NotFound")
                };
            }

            _entityService.DeleteEntities(headers);

            return new JsonResult() { Data = "success" };
        }

        public ActionResult EditHeader(int id)
        {
            var entity = _entityService.GetEntityById(id);
            entity.NullCheck("entity");

            if (entity == null)
                return RedirectToAction("HeaderList");

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/EditHeader.cshtml", entity.ToModel());
        }

        [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
        public ActionResult EditHeader(DynamicEntityHeaderModel model, bool continueEditing)
        {
            if (ModelState.IsValid)
            {
                var entity = _entityService.GetEntityById(model.Id);
                entity = model.ToEntity(entity);

                _entityService.UpdateEntityHeader(entity);

                SuccessNotification(_localizationService.GetResource("Plugins.Misc.DynamicEntity.OprationSuccess"));

                if (continueEditing)
                {
                    return RedirectToAction("EditHeader", new { id = entity.Id });
                }
                return RedirectToAction("HeaderList");
            }

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/EditHeader.cshtml", model);
        }

        public ActionResult EditItemPopu(int headerId, int? itemId)
        {
            var header = _entityService.GetEntityById(headerId);

            if (header == null)
                return RedirectToAction("EditHeader", new { id = headerId });

            var model = new DynamicEntityItemModel();
            if (itemId.HasValue == false || itemId == 0)
                model.Header = header.ToModel();
            else
                model = _entityService.GetEntityItemById(itemId.Value).ToModel();

            model.Header = header.ToModel();

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/EditItemPopu.cshtml", model);
        }

        [HttpPost]
        public ActionResult EditItemPopu(DynamicEntityItemModel model)
        {
            var header = _entityService.GetEntityById(model.HeaderId);
            if (header == null)
                return RedirectToAction("EditHeader", new { id = model.HeaderId });

            model.Header = header.ToModel();

            if (ModelState.IsValid)
            {
                if (model.Id > 0)
                {
                    var item = _entityService.GetEntityItemById(model.Id);
                    _entityService.UpdateEntityItem(model.ToEntity(item));
                }
                else
                {
                    var item = new DynamicEntityItem();
                    _entityService.InsertEntityItem(model.ToEntity(item));
                }

                ViewBag.CloseModal = true;
            }

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/EditItemPopu.cshtml", model);
        }

        public ActionResult EditItem(int id)
        {
            var item = _entityService.GetEntityItemById(id);
            item.NullCheck("item");

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/EditItem.cshtml", item.ToModel());
        }

        [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
        public ActionResult EditItem(DynamicEntityItemModel model, bool continueEditing)
        {
            var entityItem = _entityService.GetEntityItemById(model.Id);
            if (entityItem == null)
                return RedirectToAction("EditHeader", new { id = model.Header.Id });

            if (ModelState.IsValid)
            {
                _entityService.UpdateEntityItem(model.ToEntity(entityItem));

                if (continueEditing)
                {
                    return RedirectToAction("EditItem", new { id = model.Id });
                }
                return RedirectToAction("EditHeader", new { id = model.HeaderId });
            }

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/EditItem.cshtml", model);
        }

        [HttpPost]
        public ActionResult QueryEntity(DataSourceRequest command, DESearchModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageBlog))
                return AccessDeniedView();

            var entities = _entityService.Query(0, 0, command.Page - 1, command.PageSize, false, false, model.Name, model.CodeName);
            var gridModel = new DataSourceResult
            {
                Data = entities.Select(x =>
                {
                    var m = x.ToModel();

                    m.CreateTimeOnUtc = _dateTimeHelper.ConvertToUserTime(x.CreateTimeOnUtc, DateTimeKind.Utc);
                    return m;
                }),
                Total = entities.TotalCount
            };

            return new JsonResult
            {
                Data = gridModel
            };
        }

        [HttpPost]
        public ActionResult QueryEntityItems(DataSourceRequest command, int headerId)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageBlog))
                return AccessDeniedView();

            var entities = _entityService.GetAllItemsByHeaderId(headerId);
            var gridModel = new DataSourceResult
            {
                Data = entities.Select(x =>
                {
                    var m = x.ToModel();

                    m.CreateTimeOnUtc = _dateTimeHelper.ConvertToUserTime(x.CreateTimeOnUtc, DateTimeKind.Utc);
                    return m;
                }),
                Total = entities.Count()
            };

            return new JsonResult
            {
                Data = gridModel
            };
        }

        [HttpPost]
        public ActionResult DeleteItems(int[] itemIds, int headerId)
        {
            var items = _entityService.GetItemsByIds(itemIds);
            if (items == null)
                return new JsonResult { Data = "items null" };

            _entityService.DeleteEntityItem(items);

            return new JsonResult { Data = "success" };
        }

        public ActionResult Generate()
        {
            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/Generate.cshtml", new GenerateEntityModel());
        }

        [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
        public ActionResult Generate(GenerateEntityModel model, bool continueEditing)
        {
            if (ModelState.IsValid)
            {
                var settings = _settingService.LoadSetting<DynamicEntitySettings>();

                //调用WebApi获取方法参数列表
                var remote = new RemoteCall();
                var paramsToPost = new Dictionary<string, string>();
                paramsToPost.Add("SapInstance", model.SAPInstance);
                paramsToPost.Add("FunctionName", model.SAPFunctionName);

                try
                {
                    string json = remote.HttpPost(settings.SAPFunctionToken, paramsToPost);

                    //解析参数列表
                    JArray jsonObj = JArray.Parse(json);

                    //构建实体对象
                    DynamicEntityHeader header = this.buildEntity(model.SAPInstance, model.SAPFunctionName, DateTime.UtcNow, jsonObj);

                    //入库
                    this._entityService.InsertEntity(header);
                    SuccessNotification(_localizationService.GetResource("Plugins.Misc.DynamicEntity.OprationSuccess"));

                    if (continueEditing)
                    {
                        return RedirectToAction("Generate", model);
                    }
                    return RedirectToAction("HeaderList");
                }
                catch (Exception ex)
                {
                    throw;
                }
            }

            return View("~/Plugins/SDF.Plugin.Misc.DynamicEntity/Views/DynamicEntity/Generate.cshtml", model);
        }

        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure()
        {
            //load settings for a chosen project scope
            var ProjectScope = this.GetActiveProjectScopeConfiguration(_projectService, _workContext);
            var nivoSliderSettings = _settingService.LoadSetting<DynamicEntitySettings>(ProjectScope);
            var model = new ConfigurationModel();

            if (ProjectScope > 0)
            {

            }

            return View("~/Plugins/Widgets.DynamicEntity/Views/DynamicEntity/Configure.cshtml", model);
        }

        [HttpPost]
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure(ConfigurationModel model)
        {
            //load settings for a chosen project scope
            var ProjectScope = this.GetActiveProjectScopeConfiguration(_projectService, _workContext);
            var nivoSliderSettings = _settingService.LoadSetting<DynamicEntitySettings>(ProjectScope);


            /* We do not clear cache after each setting update.
             * This behavior can increase performance because cached settings will not be cleared 
             * and loaded from database after each update */

            //now clear settings cache
            _settingService.ClearCache();

            SuccessNotification(_localizationService.GetResource("Admin.Plugins.Saved"));
            return Configure();
        }

        [ChildActionOnly]
        public ActionResult PublicInfo(string widgetZone, object additionalData = null)
        {
            var nivoSliderSettings = _settingService.LoadSetting<DynamicEntitySettings>(_projectContext.CurrentProject.Id);

            var model = new PublicInfoModel();


            if (string.IsNullOrEmpty(model.Picture1Url) && string.IsNullOrEmpty(model.Picture2Url) &&
                string.IsNullOrEmpty(model.Picture3Url) && string.IsNullOrEmpty(model.Picture4Url) &&
                string.IsNullOrEmpty(model.Picture5Url))
                //no pictures uploaded
                return Content("");


            return View("~/Plugins/Widgets.DynamicEntity/Views/DynamicEntity/PublicInfo.cshtml", model);
        }

        public ActionResult ReCreateResource()
        {
            var plugin = Core.Infrastructure.EngineContext.Current.Resolve<DynamicEntityPlugin>();

            foreach (var dic in plugin._genResources())
            {
                plugin.AddOrUpdatePluginLocaleResource(dic.Key, dic.Value);
            }

            return Content("ok");
        }

        #region privateMethods

        private DynamicEntityHeader buildEntity(string sapInstance, string functionName, DateTime createTime, JArray jParams)
        {
            if (jParams == null)
                return null;

            DynamicEntityHeader header = new DynamicEntityHeader()
            {
                CodeName = $"{sapInstance}/{functionName}",
                CreateTimeOnUtc = createTime,
                Name = functionName,
                SAPInstance = sapInstance
            };

            List<DynamicEntityHeader> referenceEntities = new List<DynamicEntityHeader>();

            int sortNo = 1;
            foreach (var param in jParams)
            {
                DynamicEntityHeader referEntity = null;
                var childParams = param["ChildParams"] as JArray;

                //Table或Struct类型，则创建引用实体
                if (childParams != null)
                {
                    referEntity = buildEntity(sapInstance, $"{functionName}/{param["ParamName"].Value<string>()}", createTime, childParams);
                }

                //JToken转换为DynamicEntityItem
                DynamicEntityItem item = param.ToEntityItem(createTime, sortNo++, referEntity);

                header.Fields.Add(item);
            }

            return header;
        }


        #endregion
    }
}